package demo.db.zookeeper;

/**
 * 数据一致性是靠Paxos算法保证的，Paxos可以说是分布式一致性算法的鼻祖，是ZooKeeper的基础。
 * 
 * 通过ZooKeeper对分布式系统进行Master选举，来解决分布式系统的单点故障，保证该系统中每时每刻只有一个Master为分布式系统提供服务。
 * 
 * <h1>ZooKeeper运行模式</h1>
 * <li>"独立模式"(standalone mode)，即只有一个ZooKeeper服务器。这种模式较为简单，比较适合于测试环境，甚至可以在单元测试中采用，但是不能保证高可用性和恢复性。
 * <li>"复制模式"(replicated mode)运行于一个计算机集群上，这个计算机集群被称为一个"集合体"(ensemble)。
 * ZooKeeper通过复制来实现高可用性，只要集合体中半数以上的机器处于可用状态，它就能够提供服务。 从概念上来说，ZooKeeper它所做的就是确保对Znode树的每一个修改都会被复制到集合体中超过半数的机器上。
 * 如果少于半数的机器出现故障，则最少有一台机器会保存最新的状态，那么这台机器就是我们的Leader。其余的副本最终也会更新到这个状态。
 * 如果Leader挂了，由于其他机器保存了Leader的副本，那就可以从中选出一台机器作为新的Leader继续提供服务。
 * 
 * <h1>ZooKeeper的读写机制</h1>ZooKeeper的核心思想是，提供一个非锁机制的Wait Free的用于分布式系统同步的核心服务。
 * 提供简单的文件创建、读写操作接口，其系统核心本身对文件读写并不提供加锁互斥的服务，但是提供基于版本比对的更新操作，客户端可以基于此自己实现加锁逻辑。
 * Zookeeper是一个由多个Server组成的集群，该集群有一个Leader，多个Follower。客户端可以连接任意ZooKeeper服务节点来读写数据。 ZK集群中每个Server，都保存一份数据副本。所有的读请求由Zk
 * Server 本地响应，所有的更新请求将转发给Leader，由Leader实施。 Zookeeper使用简单的同步策略，通过以下两条基本保证来实现数据的一致性：
 * <li>① 全局串行化所有的写操作
 * <li>② 保证同一客户端的指令被FIFO执行（以及消息通知的FIFO）
 * <p>
 * <h1>组件</h1>
 * <li>ReplicatedDatabase是一个内存数据库，它包含了整个Data Tree。为了恢复，更新会被记录到磁盘，并且写在被应用到内存数据库之前，先被序列化到磁盘。
 * ZooKeeper使用自定义的原子性消息协议。由于消息传送层是原子性的，ZooKeeper能够保证本地副本不产生分歧。当leader收到一个写请求，它会计算出当写操作完成后系统将会是什么状态，接着将之转变为一个捕获状态的事务。
 * 
 * 
 * 
 */
public interface ZookeeperInfo {
    /**
     * <h1>CAP理论</h1>CAP理论的核心是：一个分布式系统不可能同时很好的满足一致性，可用性和分区容错性这三个需求，最多只能同时较好的满足两个。 CAP定理（CAP theorem）, 又被称作
     * 布鲁尔定理（Brewer's theorem）, 它指出对于一个分布式计算系统来说，不可能同时满足以下三点:
     * <li>(Consistency) 一致性：所有节点在同一时间具有相同的数据，数据一致更新，所有数据变动都是同步的。
     * <li>(Availability)可用性：系统具有好的响应性能
     * <li>(Partition tolerance)分区容错性:(系统中任意信息的丢失或失败不会影响系统的继续运作)以实际效果而言，分区相当于对通信的时限要求。
     * 系统如果不能在时限内达成数据一致性，就意味着发生了分区的情况，必须就当前操作在C和A之间做出选择，也就是说无论任何消息丢失，系统都可用。
     * <p>
     * <h2>一致性分类</h2> 一致性是指从系统外部读取系统内部的数据时，在一定约束条件下相同，即数据变动在系统内部各节点应该是同步的。根据一致性的强弱程度不同，可以将一致性级别分为如下几种：
     * <li>① 强一致性（strong consistency）。任何时刻，任何用户都能读取到最近一次成功更新的数据。
     * <li>② 单调一致性（monotonic consistency）。任何时刻，任何用户一旦读到某个数据在某次更新后的值，那么就不会再读到比这个值更旧的值。也就是说，可获取的数据顺序必是单调递增的。
     * <li>③ 会话一致性（session consistency）。任何用户在某次会话中，一旦读到某个数据在某次更新后的值，那么在本次会话中就不会再读到比这个值更旧的值。
     * 会话一致性是在单调一致性的基础上进一步放松约束，只保证单个用户单个会话内的单调性，在不同用户或同一用户不同会话间则没有保障。
     * <li>④ 最终一致性（eventual consistency）。用户只能读到某次更新后的值，但系统保证数据将最终达到完全一致的状态，只是所需时间不能保障。
     * <li>⑤ 弱一致性（weak consistency）。用户无法在确定时间内读到最新更新的值。
     * 
     */
    void cap理论();

    /**
     * ZooKeeper从以下几点保证了数据的一致性
     * <li>① 顺序一致性: 来自任意特定客户端的更新都会按其发送顺序被提交。也就是说，如果一个客户端将Znode
     * z的值更新为a，在之后的操作中，它又将z的值更新为b，则没有客户端能够在看到z的值是b之后再看到值a（如果没有其他对z的更新）。
     * <li>② 原子性: 每个更新要么成功，要么失败。这意味着如果一个更新失败，则不会有客户端会看到这个更新的结果。
     * <li>③ 单一系统映像:一个客户端无论连接到哪一台服务器，它看到的都是同样的系统视图。这意味着，如果一个客户端在同一个会话中连接到一台新的服务器，它所看到的系统状态不会比在之前服务器上所看到的更老。
     * 当一台服务器出现故障，导致它的一个客户端需要尝试连接集合体中其他的服务器时，所有滞后于故障服务器的服务器都不会接受该连接请求，除非这些服务器赶上故障服务器。
     * <li>④ 持久性: 一个更新一旦成功，其结果就会持久存在并且不会被撤销。这表明更新不会受到服务器故障的影响。
     */
    void zkAndCap();

    /**
     * Zookeeper的核心是原子广播机制，这个机制保证了各个server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式，它们分别是恢复模式和广播模式。
     * 
     * <h1>恢复模式：</h1>当服务启动或者在领导者崩溃后，Zab就进入了恢复模式，当领导者被选举出来，且大多数server完成了和leader的状态同步以后，恢复模式就结束了。
     * 状态同步保证了leader和server具有相同的系统状态。
     * <p>
     * <h1>广播模式：</h1>
     * 一旦Leader已经和多数的Follower进行了状态同步后，他就可以开始广播消息了，即进入广播状态。这时候当一个Server加入ZooKeeper服务中，它会在恢复模式下启动，发现Leader，并和Leader进行状态同步。
     * 待到同步结束，它也参与消息广播。ZooKeeper服务一直维持在Broadcast状态，直到Leader崩溃了或者Leader失去了大部分的Followers支持。
     * Broadcast模式极其类似于分布式事务中的2pc（two-phrase commit 两阶段提交）：
     * 即Leader提起一个决议，由Followers进行投票，Leader对投票结果进行计算决定是否通过该决议，如果通过执行该决议（事务），否则什么也不做。 在广播模式ZooKeeper
     * Server会接受Client请求，所有的写请求都被转发给领导者，再由领导者将更新广播给跟随者。 当半数以上的跟随者已经将修改持久化之后，领导者才会提交这个更新，然后客户端才会收到一个更新成功的响应。
     * 这个用来达成共识的协议被设计成具有原子性，因此每个修改要么成功要么失败。
     * 广播协议在所有的通讯过程中使用TCP的FIFO信道，通过使用该信道，使保持有序性变得非常的容易。通过FIFO信道，消息被有序的deliver。只要收到的消息一被处理，其顺序就会被保存下来。
     * Leader会广播已经被deliver的Proposal消息。在发出一个Proposal消息前，Leader会分配给Proposal一个单调递增的唯一id，称之为zxid。
     * 因为Zab保证了因果有序，所以递交的消息也会按照zxid进行排序。广播是把Proposal封装到消息当中，并添加到指向Follower的输出队列中，通过FIFO信道发送到
     * Follower。当Follower收到一个Proposal时，会将其写入到磁盘，可以的话进行批量写入。一旦被写入到磁盘媒介当中，Follower就会发送一个ACK给Leader。
     * 当Leader收到了指定数量的ACK时，Leader将广播commit消息并在本地deliver该消息。当收到Leader发来commit消息时，Follower也会递交该消息。
     * 
     * 
     */
    void zap协议();

    /**
     * Paxos算法就是通过投票、全局编号机制，使同一时刻只有一个写操作被批准，同时并发的写操作要去争取选票，只有获得过半数选票的写操作才会被批准，所以永远只会有一个写操作得到批准， 其他的写操作竞争失败只好再发起一轮投票
     */
    void paxos();

    /**
     * ZooKeeper 需要在所有的服务（可以理解为服务器）中选举出一个 Leader ，然后让这个 Leader 来负责管理集群。此时，集群中的其它服务器则成为此 Leader 的 Follower 。并且，当 Leader
     * 故障的时候，需要 ZooKeeper能够快速地在 Follower 中选举出下一个 Leader 。 此操作实现的核心思想是：首先创建一个 EPHEMERAL 目录节点，例如“ /election
     * ”。然后每一个ZooKeeper 服务器在此目录下创建一个 SEQUENCE| EPHEMERAL 类型的节点，例如“ /election/n_ ”。在SEQUENCE 标志下， ZooKeeper 将自动地为每一个
     * ZooKeeper 服务器分配一个比前一个分配的序号要大的序号。此时创建节点的 ZooKeeper 服务器中拥有最小序号编号的服务器将成为 Leader 。 在实际的操作中，还需要保障：当 Leader
     * 服务器发生故障的时候，系统能够快速地选出下一个 ZooKeeper 服务器作为 Leader 。一个简单的解决方案是，让所有的 follower 监视 leader 所对应的节点。当 Leader 发生故障时， Leader
     * 所对应的临时节点将会自动地被删除，此操作将会触发所有监视 Leader 的服务器的 watch 。这样这些服务器将会收到 Leader 故障的消息，并进而进行下一次的 Leader
     * 选举操作。但是，这种操作将会导致“从众效应”的发生，尤其当集群中服务器众多并且带宽延迟比较大的时候，此种情况更为明显。
     * 
     * 在 Zookeeper 中，为了避免从众效应的发生，它是这样来实现的：每一个 follower 对 follower 集群中对应的比自己节点序号小一号的节点（也就是所有序号比自己小的节点中的序号最大的节点）设置一个 watch
     * 。只有当follower 所设置的 watch 被触发的时候，它才进行 Leader 选举操作，一般情况下它将成为集群中的下一个 Leader。很明显，此 Leader 选举操作的速度是很快的。因为，每一次 Leader
     * 选举几乎只涉及单个 follower 的操作。
     * <p>
     * 
     */
    void leader选举();
}
